//this file  implement thread, event, mutex with posix
//function api
//mlcai 2011-06-12

#include "NameSpaceDef.h"
#include ADD_QUOTE(INC_NAME_HEADER(NAMESPACE_NAME, Thread.h))
#include <sys/time.h>
#include <unistd.h>

BEGIN_CXX_NAMESPACE_DEFINITION

//---------------------------implement Mutex-------------------

Mutex::Mutex()
{
	pthread_mutexattr_t attr;
	pthread_mutexattr_init(&attr);
	pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);

	pthread_mutex_init(&m_mutex, &attr);

	pthread_mutexattr_destroy(&attr);
}

Mutex::~Mutex()
{
	pthread_mutex_destroy(&m_mutex);
}

void Mutex::lock()
{
	pthread_mutex_lock(&m_mutex);
}

void Mutex::unlock()
{
	pthread_mutex_unlock(&m_mutex);
}

//------------------------implement Event----------------------

Event::Event()
{
	pthread_mutex_init(&m_mutex, NULL);
	pthread_cond_init(&m_event, NULL);
}

Event::~Event()
{
	pthread_cond_destroy(&m_event);
	pthread_mutex_destroy(&m_mutex);
}

void Event::set()
{
	pthread_mutex_lock(&m_mutex);

	pthread_cond_broadcast(&m_event);

	pthread_mutex_unlock(&m_mutex);
}

void Event::wait()
{
	pthread_mutex_lock(&m_mutex);

	pthread_cond_wait(&m_event, &m_mutex);

	pthread_mutex_unlock(&m_mutex);
}

Event::WAITRE Event::wait(long msecs)
{
	int ret = 0;
	struct timespec abstm;
	struct timeval tmv;
	gettimeofday(&tmv, NULL);
	abstm.tv_sec  = tmv.tv_sec + msecs / 1000;
	abstm.tv_nsec = tmv.tv_usec*1000 + (msecs % 1000)*1000000;
	if (abstm.tv_nsec >= 1000000000)
	{
		abstm.tv_nsec -= 1000000000;
		abstm.tv_sec++;
	}

	pthread_mutex_lock(&m_mutex);

	ret = pthread_cond_timedwait(&m_event, &m_mutex, &abstm);

	pthread_mutex_unlock(&m_mutex);

	return (ret == 0) ? OK : TIMEOUT;
}

//-------------------------implement Thread--------------------

Thread::Thread() : m_isThreadBegin(false)
{
}

Thread::~Thread()
{
}

void Thread::start()
{
	pthread_attr_t attr;
	pthread_attr_init(&attr);

	pthread_create(&m_tid, &attr, thread_fun, this);
}

void Thread::join()
{
	void* re;
	pthread_join(m_tid, &re);
}

void Thread::sleep(long secs)
{
	::sleep(secs);
}

void Thread::msleep(long msecs)
{
	::usleep(msecs * 1000);
}

void Thread::usleep(long usecs)
{
	::usleep(usecs);
}

void* Thread::thread_fun(void* arg)
{
	Thread* thr = static_cast<Thread*>(arg);
	thr->m_isThreadBegin = true;
	thr->run();
	thr->m_isThreadBegin = false;
	return thr;
}

END_CXX_NAMESPACE_DEFINITION
